package cn.tedu.lucky.draw.server.service.impl;


import cn.tedu.lucky.draw.server.common.enums.DrawEnum;
import cn.tedu.lucky.draw.server.common.handler.DrawException;
import cn.tedu.lucky.draw.server.protocol.po.*;
import cn.tedu.lucky.draw.server.protocol.query.ActivityQuery;
import cn.tedu.lucky.draw.server.repository.ActivityRepository;
import cn.tedu.lucky.draw.server.repository.ActivityRuleRepository;
import cn.tedu.lucky.draw.server.repository.ResultRepository;
import cn.tedu.lucky.draw.server.repository.RuleRepository;
import cn.tedu.lucky.draw.server.service.IActivityRuleService;
import cn.tedu.lucky.draw.server.service.IActivityService;
import cn.tedu.lucky.draw.server.service.IPrizeService;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ActivityServiceImpl implements IActivityService {

    @Autowired
    private ActivityRepository activityRepository;

    @Autowired
    @Lazy
    private IActivityRuleService activityRuleService;

    @Autowired
    private ResultRepository resultRepository;

    @Autowired
    @Lazy
    private IPrizeService prizeService;

    private List<Activity> activities;


    @Override
    public List<Activity> findAll(ActivityQuery activityQuery) {
        if (activities == null) {
            activities = activityRepository.findAll();
        }
        String name = activityQuery.getName();
        Integer status = activityQuery.getStatus();
        return activities.stream()
                .filter(activity -> name == null || name == "" || name.equals(activity.getName()))
                .filter(activity -> status == null || status.equals(activity.getStatus()))
                .collect(Collectors.toList());
    }


    @Override
    public void save(Activity activity) {
        LocalDateTime now = LocalDateTime.now();
        activity.setCreateTime(now);
        activity.setUpdateTime(now);
        activity.setStatus(0);//待审核
        activityRepository.save(activity);
        activities = null;
    }

    @Override
    public Activity findActivityById(Long id) {
        Optional<Activity> optional = activityRepository.findById(id);
        if (optional.isPresent()) {
            return optional.get();
        }
        return null;
    }

    @Override
    public Prize trigger(Long activityId) throws JSONException {
        //1.获取活动的规则，检测用户是否具备参与条件
        List<Rule> ruleList = activityRuleService.findRuleByActivityId(activityId);
        boolean value = false;
        for (Rule rule : ruleList) {
            if (rule.getType() == 1) {
                //获取当前活动配置的抽奖次数
                JSONObject jsonObject = new JSONObject(rule.getContent());
                //抽奖次数
                int count = jsonObject.getInt("count");
                //用户ID
                Long userId = getUserId();
                //获取用户抽奖次数
                Integer result = resultRepository.countByActivityIdAndUserId(activityId, userId);
                if (result >= count) {
                    throw new DrawException(DrawEnum.TIMES_EXHAUSTED);
                }
            } else if (rule.getType() == 2) {
                //检测概率是否降低
                JSONObject jsonObject = new JSONObject(rule.getContent());
                value = jsonObject.getBoolean("value");
            }
        }

        //2.获取活动奖品，用于计算中奖结果
        List<Prize> prizeList = prizeService.findAllByActivityId(activityId);

        //3.常规的抽奖算法，根据不通干的特地应用场景及特点，会存在不同的抽奖算法
        HashMap<Prize, Double> prizeDoubleHashMap = new HashMap<>();
        //总逆价值
        double invserseValue = prizeList.stream().mapToDouble(prize -> 1.0 / prize.getValue()).sum();
        double factor = value ? 0.5 : 1.0;
        for (Prize prize : prizeList) {
            double prizeInvserseValue = (1.0 / prize.getValue()) / invserseValue;
            prizeDoubleHashMap.put(prize, prizeInvserseValue * factor);
        }
        //执行抽奖
        double randomValue = new Random().nextDouble();
        double calculateValue = 0.0;
        for (Map.Entry<Prize, Double> entry : prizeDoubleHashMap.entrySet()) {
            Prize prize = entry.getKey();
            calculateValue += entry.getValue();
            if (randomValue <= calculateValue) {
                prize.setStock(prize.getStock() - 1);
                prizeService.save(prize);
                saveActivityResult(activityId, prize.getId());
                return prize;
            }
        }
        //如果没有抽中任何奖品
        Prize prize = new Prize();
        prize.setId(99999999999L);
        prize.setName("谢谢参与");
        prize.setImg("https://lucky-draw.oss-cn-beijing.aliyuncs.com/no-prize.jpg");
        saveActivityResult(activityId, prize.getId());
        return prize;
    }

    private void saveActivityResult(Long activityId, Long prizeId) {
        Result result = new Result();
        result.setActivityId(activityId);
        result.setPrizeId(prizeId);
        result.setUserId(getUserId());
        result.setWinTime(LocalDateTime.now());
        //未发放
        result.setStatus(0);
        resultRepository.save(result);
    }


    public Long getUserId() {
        return 1L;
    }


}
